docs: add scripts/uq-publish.py for understand-quickly registry integration#332
Open
amacsmith wants to merge 2 commits intoDeusData:mainfrom
Open
docs: add scripts/uq-publish.py for understand-quickly registry integration#332amacsmith wants to merge 2 commits intoDeusData:mainfrom
amacsmith wants to merge 2 commits intoDeusData:mainfrom
Conversation
…ration
Adds a small Python helper (stdlib-only — no new dependencies, no C
changes, no impact on the binary) that:
1. Drives the existing cbm binary over stdio MCP to extract graph
contents via `get_architecture`.
2. Projects to a `gitnexus@1`-shaped JSON file at
`.codebase-memory/graph.json` with `metadata.{tool, tool_version,
generated_at, commit}`.
3. If `UNDERSTAND_QUICKLY_TOKEN` is set, fires a
`repository_dispatch` at `looptech-ai/understand-quickly` so the
registry resyncs the entry.
This preserves the "single static binary, zero dependencies" property —
the script is opt-in and lives under `scripts/`, alongside other Python
helpers like `scripts/test_mcp_rapid_init.py`. Two unit tests with
stdlib `unittest`.
Spec: https://github.com/looptech-ai/understand-quickly/blob/main/docs/spec/code-graph-protocol.md
Action: https://github.com/looptech-ai/uq-publish-action
There was a problem hiding this comment.
Pull request overview
Adds an opt-in, stdlib-only publishing helper to project codebase-memory-mcp graphs into an understand-quickly-compatible artifact (.codebase-memory/graph.json) and optionally trigger a registry resync via GitHub repository_dispatch.
Changes:
- Added
scripts/uq-publish.pyto extract graph info via MCP over stdio, writegitnexus@1JSON, and optionally dispatch a sync event. - Added
scripts/test_uq_publish.py(stdlibunittest) for basic coverage of graph projection + metadata stamping. - Updated
README.mdwith an “Publish to understand-quickly (opt-in)” section and recommended CI action snippet.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| README.md | Documents the opt-in publish workflow, including local-only behavior without a token and the suggested CI action. |
| scripts/uq-publish.py | Implements MCP stdio invocation, graph JSON emission, metadata stamping, and optional GitHub dispatch. |
| scripts/test_uq_publish.py | Adds unit tests for metadata stamping and graph projection logic. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+74
to
+81
| for line in proc.stdout.splitlines(): | ||
| try: | ||
| obj = json.loads(line) | ||
| except json.JSONDecodeError: | ||
| continue | ||
| if obj.get("id") == 2: | ||
| return obj.get("result", {}) | ||
| raise RuntimeError(f"no response from {binary} for tool {tool}") |
Comment on lines
+84
to
+99
| def build_graph(binary: str, project: str) -> dict: | ||
| """Project the in-memory KG to a `gitnexus@1`-shaped graph using existing MCP tools.""" | ||
| arch = _mcp_call(binary, "get_architecture", {"project": project}) | ||
| nodes_raw = arch.get("nodes") or arch.get("modules") or [] | ||
| edges_raw = arch.get("edges") or arch.get("links") or [] | ||
| nodes = [ | ||
| {"id": str(n.get("id", n.get("name", i))), | ||
| "label": n.get("name", n.get("label", "")), | ||
| "kind": n.get("kind", n.get("type", "module"))} | ||
| for i, n in enumerate(nodes_raw) | ||
| ] | ||
| edges = [ | ||
| {"source": str(e.get("source", e.get("from", ""))), | ||
| "target": str(e.get("target", e.get("to", ""))), | ||
| "kind": e.get("kind", e.get("type", "depends_on"))} | ||
| for e in edges_raw |
Comment on lines
+51
to
+61
| fake_arch = { | ||
| "nodes": [{"id": 1, "name": "AuthService", "kind": "module"}], | ||
| "edges": [{"source": 1, "target": 2, "kind": "depends_on"}], | ||
| } | ||
| with mock.patch.object(uq, "_mcp_call", return_value=fake_arch): | ||
| graph = uq.build_graph("/fake/binary", "demo") | ||
| self.assertEqual(graph["schema"], "gitnexus@1") | ||
| self.assertEqual(len(graph["nodes"]), 1) | ||
| self.assertEqual(graph["nodes"][0]["label"], "AuthService") | ||
| self.assertEqual(len(graph["links"]), 1) | ||
| self.assertEqual(graph["links"][0]["source"], "1") |
Comment on lines
+40
to
+56
| def _git(args: list[str], cwd: Path) -> str | None: | ||
| try: | ||
| r = subprocess.run( # nosec B603 | ||
| ["git", *args], cwd=str(cwd), capture_output=True, text=True, | ||
| check=False, timeout=5, | ||
| ) | ||
| except (FileNotFoundError, subprocess.SubprocessError): | ||
| return None | ||
| return r.stdout.strip() if r.returncode == 0 else None | ||
|
|
||
|
|
||
| def _detect_repo_slug(cwd: Path) -> str | None: | ||
| url = _git(["remote", "get-url", "origin"], cwd) or "" | ||
| for prefix in ("https://github.com/", "git@github.com:"): | ||
| if url.startswith(prefix): | ||
| slug = url[len(prefix):].removesuffix(".git") | ||
| return slug or None |
Comment on lines
+154
to
+160
| try: | ||
| graph = build_graph(args.binary, args.project) | ||
| except Exception as exc: | ||
| print(f"[uq-publish] could not extract graph via {args.binary}: {exc}", | ||
| file=sys.stderr) | ||
| return 1 | ||
|
|
…edges Address Copilot review on PR DeusData#332: - _mcp_call now unwraps the MCP `{content:[{type:'text',text:'...'}]}` envelope and json.loads the inner text; raises RuntimeError on isError. Previously callers saw the raw envelope, so build_graph silently produced empty graphs. - build_graph now uses two query_graph Cypher queries to fetch Module nodes and their dependency edges instead of get_architecture, which returns counts/summaries (total_nodes, node_labels, edge_types) — never a node/edge list. - Replace Python 3.10+ `str | None` annotations with `Optional[str]` and drop `removesuffix` (3.9+) for broader Python compatibility. - Tests now mock the new _query_rows interface and add explicit coverage for the MCP envelope unwrap (success + isError paths). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Author
|
Thanks for the Copilot review — addressed the real correctness findings in 87491f2:
Skipped style-only nits (e.g. exit-code wording in PR description). Happy to adjust further. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
looptech-ai/understand-quicklyis a public registry of code-knowledge graphs that ships its own MCP server and a stableregistry.jsonAPI. codebase-memory-mcp is itself an MCP server backed by a persistent code-knowledge graph — the registry is the natural place for those graphs to be discovered by other agents (Claude, Codex, Cursor) without each user pointing at a private endpoint.This PR ships the integration as a small Python helper (
scripts/uq-publish.py) that drives the existing MCP surface — no C changes, no new dependencies in the binary, no rebuild needed. The "single static binary, zero dependencies" property is preserved.What changes
scripts/uq-publish.py(stdlib-only —urllib,subprocess,json).scripts/test_uq_publish.pyusing stdlibunittest.When run, the script:
codebase-memory-mcpbinary, sendsinitialize+notifications/initialized+tools/call get_architectureover stdio (the same pattern used by the existingscripts/test_mcp_rapid_init.py).gitnexus@1-shaped JSON graph ({schema, nodes, links}).metadata.{tool, tool_version, generated_at, commit}(commit viagit rev-parse HEAD)..codebase-memory/graph.json.$UNDERSTAND_QUICKLY_TOKENis set, fires arepository_dispatchevent atlooptech-ai/understand-quicklyso the registry's sync workflow re-pulls the entry. If unset, only the local file is written — no network call.The recommended CI step is the
looptech-ai/uq-publish-action@v0.1.0Marketplace Action (which collapses the dispatch step to ~5 lines of YAML).Diff stats
The publish script is 201 LoC; the rest is tests + docs.
No-op default
The script is entirely opt-in (no auto-invoke, no hook). Running it without
UNDERSTAND_QUICKLY_TOKENwrites only the local file. Running it with the token but the repo not yet registered prints a one-line registration hint and exits 0. Failures (network, missing remote, missing binary) never raise — they print a single line and return cleanly so a CI job using this script in a non-publish context isn't broken.Schema fit
The script writes
gitnexus@1({nodes, links}arrays plusmetadata) — the closest existing schema in the registry. If you'd later prefer a richercbm@1schema with shape-specific data (LSP-resolved type info, HTTP route nodes, ADR nodes), the registry has a format-authoring path — happy to co-author it as a follow-up.Test plan
python3 scripts/test_uq_publish.py— 2 tests pass.python3 scripts/uq-publish.py /path/to/cbmagainst a real-indexed project writes.codebase-memory/graph.jsonwith stamped metadata.UNDERSTAND_QUICKLY_TOKENset and the repo registered, dispatch fires and the registry'ssync.ymlruns within ~1 minute.Notes
--publishflag baked directly intocbm(a C-side implementation), I'm happy to follow up with a separate PR; the script can serve as the reference implementation.DeusData/codebase-memory-mcpto the verified-publisher allowlist for auto-merge of registry updates.UNDERSTAND_QUICKLY_TOKEN.Links
gitnexus@1schema: https://github.com/looptech-ai/understand-quickly/blob/main/schemas/gitnexus@1.json